其他
一次 SQL 查询优化原理分析(900W+ 数据,从 17s 到 300ms)
这里是码农充电第一站,回复“666”,获取一份专属大礼包 真爱,请设置“星标”或点个“在看”
一,前言 证实 参考资料
操作: 查询条件放到子查询中,子查询只查主键ID,然后使用子查询中确定的主键关联查询其他的属性字段; 原理: 减少回表操作;
SELECT 各种字段
FROM `table_name`
WHERE 各种条件
LIMIT 0,10;
SELECT 各种字段
FROM `table_name` main_tale
RIGHT JOIN
(
SELECT 子查询只查主键
FROM `table_name`
WHERE 各种条件
LIMIT 0,10;
) temp_table ON temp_table.主键 = main_table.主键
一,前言
+-----------+
| version() |
+-----------+
| 5.7.17 |
+-----------+
1 row in set (0.00 sec)
+--------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| val | int(10) unsigned | NO | MUL | 0 | |
| source | int(10) unsigned | NO | | 0 | |
+--------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
+----------+
| count(*) |
+----------+
| 5242882 |
+----------+
1 row in set (4.25 sec)
+---------+-----+--------+
| id | val | source |
+---------+-----+--------+
| 3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (15.98 sec)
+---------+-----+--------+---------+
| id | val | source | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.38 sec)
证实
select * from test where val=4 limit 300000,5
是扫描300005个索引节点和300005个聚簇索引上的数据节点,我们需要知道MySQL有没有办法统计在一个sql中通过索引节点查询数据节点的次数。我先试了Handler_read_*系列,很遗憾没有一个变量能满足条件。select * from test a inner join (select id from test where val=4 limit 300000,5);
之后,buffer pool中的数据页的数量远远少于select * from test where val=4 limit 300000,5;
对应的数量,因为前一个sql只访问5次数据页,而后一个sql访问300005次数据页。+---------+-----+--------+
| id | val | source |
+---------+-----+--------+|
3327622 | 4 | 4 |
| 3327632 | 4 | 4 |
| 3327642 | 4 | 4 |
| 3327652 | 4 | 4 |
| 3327662 | 4 | 4 |
+---------+-----+--------+
5 rows in set (26.19 sec)
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY | 4098 |
| val | 208 |
+------------+----------+2 rows in set (0.04 sec)
select * from test a inner join (select id from test where val=4 limit 300000,5) ;
为了防止上次试验的影响,我们需要清空buffer pool,重启mysql。/usr/local/bin/mysqld_safe &
Empty set (0.03 sec)
+---------+-----+--------+---------+
| id | val | source | id |
+---------+-----+--------+---------+
| 3327622 | 4 | 4 | 3327622 |
| 3327632 | 4 | 4 | 3327632 |
| 3327642 | 4 | 4 | 3327642 |
| 3327652 | 4 | 4 | 3327652 |
| 3327662 | 4 | 4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.09 sec)
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY | 5 |
| val | 390 |
+------------+----------+
2 rows in set (0.03 sec)
参考资料
---END--- 重磅!鱼哥微信好友坑位限时开放啦!
扫码直接加鱼哥微信号,不仅可以围观鱼哥平时所思和复盘的内容。还可以帮你免费内推大厂,技术交流,一起探索职场突围,收入突围,技术突围。一定要备注:开发方向+地点+学校/公司+昵称(如Java开发+上海+拼夕夕+猴子)
▲长按加鱼哥微信,赶紧上车
扫码直接加鱼哥微信号,不仅可以围观鱼哥平时所思和复盘的内容。还可以帮你免费内推大厂,技术交流,一起探索职场突围,收入突围,技术突围。一定要备注:开发方向+地点+学校/公司+昵称(如Java开发+上海+拼夕夕+猴子)
推荐阅读
• 再见,VPN !• 微信支付的软件架构也太特么牛逼了吧...• 大厂的 404 页面都长啥样?看到最后一个,我笑了...• GitHub 重大更新:在线开发上线,是时候卸载 IDE 了• IntelliJ IDEA 更新后,电脑卡成球,该如何优化?• 用Java写一个植物大战僵尸简易版!欢迎关注我的公众号“码农突围”,如果喜欢,麻烦点一下“在看”~